package com.icesoft.core.web.configurer.task;

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryType;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import com.icesoft.core.web.base.BaseJvmRunWarn;
import com.icesoft.core.web.configurer.test.condition.ConditionOnNotMockTestCase;

import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;

@Configuration
@EnableScheduling
@ConditionalOnClass(MeterRegistry.class)
@ConditionOnNotMockTestCase
public class ApplicationStateSchedule {
	protected final Logger log = LoggerFactory.getLogger(this.getClass());

	static String toMb(long s) {
		return toMb((double) s);
	}

	static String toMb(double s) {
		return (int) (s / (1024 * 1024)) + " M";
	}

	@Autowired
	@Lazy
	MeterRegistry meterRegistry;

	private double findMeter(String meterName) {
		Gauge gauge = meterRegistry.find(meterName).gauge();
		if (gauge == null) {
			return 0;
		}
		return gauge.value();
	}

	@Autowired(required = false)
	List<BaseJvmRunWarn> baseJvmRunWarns;

	@Scheduled(initialDelay = 10000, fixedDelay = 30000)
	protected void schedule() {

		int currentTomcatThreads = (int) findMeter("tomcat.threads.busy");
		int maxTomcatThreads = (int) findMeter("tomcat.threads.config.max");
		double maxRequestTimes = findMeter("tomcat.global.request.max");
		int activeJdbcConnections = (int) findMeter("jdbc.connections.active");
		int maxJdbcConnections = (int) findMeter("jdbc.connections.max");
		int jvmLiveThreads = (int) findMeter("jvm.threads.live");
		int jvmPeakThreads = (int) findMeter("jvm.threads.peak");
		double jvmMemoryUsed = findMeter("jvm.memory.used");
		StringBuilder sb = new StringBuilder("---------->\n");
		if (maxTomcatThreads != 0) {
			sb.append("tomcat当前线程数：").append(currentTomcatThreads).append("，");
			sb.append("tomcat允许的最大线程数：").append(maxTomcatThreads).append("，");
			sb.append("tomcat请求时间峰值：").append(maxRequestTimes).append("s\n");
		}
		sb.append("jvm当前线程数：").append(jvmLiveThreads).append("，");
		sb.append("jvm峰值线程数：").append(jvmPeakThreads).append("，");
		sb.append("jvm内存使用：").append(toMb(jvmMemoryUsed)).append("\n");
		if (maxJdbcConnections != 0) {
			sb.append("jdbc当前连接数：").append(activeJdbcConnections).append("，");
			sb.append("jdbc允许的最大连接数：").append(maxJdbcConnections).append("\n");
		}

		for (MemoryPoolMXBean mp : ManagementFactory.getMemoryPoolMXBeans()) {
			if (mp.getType() == MemoryType.HEAP) {
				sb.append(mp.getName() + " = " + toMb(mp.getUsage().getMax())).append(", ");
			}
		}
		sb.append("\n");
		sb.append("Runtime max: " + toMb(Runtime.getRuntime().maxMemory())).append(", ");
		sb.append("total usage: " + toMb(Runtime.getRuntime().totalMemory())).append(", ");
		sb.append("free usage: " + toMb(Runtime.getRuntime().freeMemory())).append("\n");
		if (currentTomcatThreads == 0) {
			if (maxTomcatThreads != 0) {
				if (log.isTraceEnabled()) {
					log.trace(sb.toString());
				} else {
					if (jvmLiveThreads > maxTomcatThreads) {
						log.info(sb.toString());
					}
				}
			}

		} else if (maxTomcatThreads != 0) {
			if (maxTomcatThreads - currentTomcatThreads > 50) {
				log.debug(sb.toString());
			} else {
				log.info(sb.toString());
			}
		}

		if (baseJvmRunWarns != null) {
			for (BaseJvmRunWarn baseJvmRunWarn : baseJvmRunWarns) {
				if (maxTomcatThreads != 0 && currentTomcatThreads != 0
						&& maxTomcatThreads - currentTomcatThreads < baseJvmRunWarn.tomcatThreadWarnCount()) {
					baseJvmRunWarn.tomcatThreadWarn();
				}
				if (maxJdbcConnections != 0 && activeJdbcConnections != 0
						&& maxJdbcConnections - activeJdbcConnections < baseJvmRunWarn.JdbcConnectionWarnCount()) {
					baseJvmRunWarn.JdbcConnectionWarn();
				}
			}
		}
	}
}
